package proxynew;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Enumeration;

import net.jxta.endpoint.ByteArrayMessageElement;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.StringMessageElement;
import net.jxta.pipe.OutputPipe;
import net.jxta.pipe.PipeService;
import net.jxta.platform.NetworkManager;
import net.jxta.socket.JxtaMulticastSocket;

public class MulticastSniffer extends Thread {
	String ip;
	String port;
	
	NetworkManager networkManager;
	JxtaMulticastSocket mcastSocket;

	public MulticastSniffer(String group, NetworkManager networkManager) {
		this.ip = group.split(":")[0];
		this.port = group.split(":")[1];
		this.networkManager = networkManager;
		System.out.println("MulticastSniffer: Criando MulticastSniffer para ip " + this.ip + " porta " + this.port);
	}
	
	public void run () {
		// cria conexão com grupo multicast
		InetAddress ia = null;
		try {
			ia = InetAddress.getByName(this.ip);
		} catch (UnknownHostException e) {
			System.err.println("MulticastSniffer: Não foi possivel abrir socket para " + this.ip + ":" + this.port);
			ia = null;
		}
		int port = Integer.parseInt(this.port);

		if (ia != null) {
			while (true) {
				try {
					// recebe conexões para um determinado grupo multicast
					MulticastSocket multicastSocket = new MulticastSocket(port);
					multicastSocket.joinGroup(ia);
					
					DatagramPacket datagram = receiveMulticastMessage(multicastSocket);
					System.out.println("MulticastSniffer: Mensagem recebida do grupo " + this.ip + " porta " + this.port + " conteudo = [" +  (new String (datagram.getData())).substring(0, datagram.getLength()) + "]");
					sendMessageToOverlay(datagram);
				} catch (IOException e) { 
					e.printStackTrace();
				}
			}
		}
	}

//					while(true) {
//					    byte[] buffer = new byte[65535];
//					    DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
//	
//						ms.receive(dp);
//						String m1 = new String (dp.getData());
//						String message = m1.substring(0, m1.indexOf(0));
//						System.out.println("MulticastSniffer: Mensagem recebida do grupo " + this.ip + " porta " + this.port + " conteudo = [" + message + "]");
//						
//						byte[] send_buffer = createPacket(message);
//											
//						mcastSocket.setLoopbackMode(true); 
//						System.out.println("MulticastSniffer: Enviando pacote para overlay com " + send_buffer.length + " bytes.");
////						overlaySocket.send(new DatagramPacket(send_buffer, send_buffer.length));
//						mcastSocket.send(new DatagramPacket(send_buffer, send_buffer.length));
//						System.out.println(new String(send_buffer));
//					}	
//				} catch (IOException e) {
//					System.err.println("MulticastSniffer: Exceção recebendo pacote. " + e.getMessage());
//					e.printStackTrace();
//				}
//		}
//	}
	
	private DatagramPacket receiveMulticastMessage(MulticastSocket multicastSocket) throws IOException {
	    byte[] buffer = new byte[65535];
	    DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
		multicastSocket.receive(dp);
		//System.out.println("MulticastSniffer: Received ttl: " + multicastSocket.getTimeToLive() + " ip " + dp.getAddress()  + " is local " + dp.getAddress().isLinkLocalAddress());
		//System.out.println("Network Interface: " + NetworkInterface.getByInetAddress(dp.getAddress()));
		return dp;
	}

	private void sendMessageToOverlay(DatagramPacket datagram) {
		Message message = new Message();
		StringMessageElement group = new StringMessageElement("group", this.ip + ":" + this.port, null);		
		message.addMessageElement(group);
		
		byte[] buffer = Arrays.copyOf(datagram.getData(), datagram.getLength());
		ByteArrayMessageElement data = new ByteArrayMessageElement("data", null, buffer, null);
		message.addMessageElement(data);

		PipeService pipeService = networkManager.getNetPeerGroup().getPipeService();
		Enumeration<String> iterPipes = Pipes.getInstance().getPipes();
		while (iterPipes.hasMoreElements()) {
			String pipe = (String) iterPipes.nextElement();
			try {
				if (!PipeMsgListener.getPideID().toString().equalsIgnoreCase(pipe)) {
					System.out.println("Sending message to " + pipe);
					OutputPipe outPipe = pipeService.createOutputPipe(Pipes.getInstance().getAdvertisement(pipe), 30 * 1000);
					outPipe.send(message);
					outPipe.close();
				}
			} catch (IOException e) {
				System.err.println("MulticastSniffer: Could not send message to pipe, removing it from list: " + pipe);
				Pipes.getInstance().removePipe(pipe);
				e.printStackTrace();
			}
		}
	}

	private byte[] createPacket(String message) {
		
		//byte[] new_packet = new byte[dp.getData().length + 25];
		//byte[] new_packet =  Arrays.copyOf(message.getBytes(), message.getBytes().length + 25);
	
		String m1 = this.ip + ":" + this.port;
		String m2 = m1 + fill_spaces(25 - m1.length());
		
		return (message + m2).getBytes();
		
/*		int i = message.getBytes().length;
		for (char c : this.ip.toCharArray()) {
			if (c == '.') 
				new_packet[i] = (byte)0;
			else
				new_packet[i] = (byte) Integer.parseInt(String.valueOf(c));
			
			i++;
		}
		new_packet[i++] = 0;
		for (char c: this.port.toCharArray()) {
			new_packet[i++] = (byte) Integer.parseInt(String.valueOf(c));
		}
		
		return new_packet;
		  */
	}

	private String fill_spaces(int num) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < num; i++) {
			sb.append(" ");
		}
		return sb.toString();
	}

}
